package com.longkey.workflow.client.util
{
	import flash.geom.Point;
	
	import mx.geom.RoundedRectangle;

	public class MathUtil
	{				
		private static function calcEllipseIntersection(center:Point, a:Number, b:Number, ratio:Number, outter:Point):Point{
			var intersection:Point = new Point();
			var m:Number = Math.abs(center.x - outter.x);
			var n:Number = Math.abs(center.y - outter.y);
			var area:Number = 1;
			if(ratio <= 1){
				area = m*m/a*a + n*n/b*b;	
			}
			else{
				area = n*n/a*a + m*m/b*b;
			}
			if(area < 1){
				intersection.x = center.x;
				intersection.y = center.y;
			}
			else if(area == 1){
				intersection.x = outter.x;
				intersection.y = outter.y;
			}
			else{
				var x:Number = 0;
				var y:Number = 0;
				if(ratio > 1){
					x = (a*b*m)/Math.sqrt(m*m*b*b + n*n*a*a);
					y = (a*b*n)/Math.sqrt(m*m*b*b + n*n*a*a);
				}
				else{
					x = (a*b*m)/Math.sqrt(n*n*b*b + m*m*a*a);
					y = (a*b*n)/Math.sqrt(n*n*b*b + m*m*a*a);
				}
				if(outter.x > center.x){
					intersection.x = Math.round(center.x + x);
				}
				else{
					intersection.x = Math.round(center.x - x);
				}
				if(outter.y > center.y){
					intersection.y = Math.round(center.y + y);
				}
				else{
					intersection.y = Math.round(center.y - y);
				}
			}
			return intersection;
		}
		
		public static function calcEllipseIntersectPoint(center:Point, width:Number, height:Number, outter:Point):Point{
			var a:Number = Math.max(width/2, height/2);
			var b:Number = Math.min(width/2, height/2);
			var ratio:Number = width/height;
			return MathUtil.calcEllipseIntersection(center, a, b, ratio, outter);
		}
		
		public static function calcRoundIntersectPoint(center:Point, radius:Number, outter:Point):Point{
			return MathUtil.calcEllipseIntersection(center, radius, radius, 1, outter);
		}		
		
		public static function calcRoundRectIntersectPoint(center:Point, width:Number, height:Number, radius:Number, outter:Point):Point{
			var rect:RoundedRectangle = new RoundedRectangle(center.x - width/2, center.y - height/2, width, height, radius);
			if(rect.containsPoint(outter)){
				return center;
			}
			var offx:Number = 0;
			var offy:Number = 0;
			
			var m:Number = Math.abs(center.x - outter.x);
			var n:Number = Math.abs(center.y - outter.y);

			if(n == 0){
				offx = width/2;
				offy = 0;
			}
			else if(m == 0){
				offx = 0;
				offy = height/2;
			}
			else{
				var r:Number = rect.cornerRadius;
				var p0:Point = new Point();
				p0.x = width/2 - r;
				p0.y = height/2 - r;
				var p1:Point = new Point();
				p1.x = width/2;
				p1.y = p0.y;
				var p2:Point = new Point();
				p2.x = p0.x;
				p2.y = height/2;
				var angle1:Number = p1.y/p1.x;
				var angle2:Number = p2.y/p2.x;
				var angle:Number = n/m;
				if(angle <= angle1){
					offx = width/2;
					offy = (n*width)/(2*m);
				}
				else if(angle >= angle2){
					offx = (m*height)/(2*n);
					offy = height/2;
				}
				else{
					var pout:Point = new Point();
					pout.x = m - p0.x;
					pout.y = n - p0.y;
					var p:Point = MathUtil.calcRoundIntersectPoint(p0, r, pout);
					offx = p.x;
					offy = p.y;
				}
				//trace("r:" + r + " angle:" + angle + ",angle1:" + angle1 + ",angle2:" + angle2);
			}
			
			var intersection:Point = new Point();
			if(outter.x >= center.x){
				intersection.x = center.x + offx;
			}
			else{
				intersection.x = center.x - offx;
			}
			if(outter.y >= center.y){
				intersection.y = center.y + offy;
			}
			else{
				intersection.y = center.y - offy;
			}
			//trace("center" + center + ", off(" + offx + "," + offy + ")");
			return intersection;
		}
		
		private static function calcClosestPointOnLine(from:Point, to:Point, outter:Point):Point{
			var px:Number = to.x - from.x;
			var py:Number = to.y - from.y;
			var som:Number = px*px + py*py;
			var u:Number = ((outter.x-from.x)*px + (outter.y-from.y)*py)/som;
			if(u > 1){
				u = 1;
			}
			else if(u < 0){
				u = 0;
			}
			var p:Point = new Point();
			p.x = from.x + u*px;
			p.y = from.y + u*py;
			return p;
		}
		
		public static function calcDistance(from:Point, to:Point):Number{
			var dx:Number = to.x - from.x;
			var dy:Number = to.y - from.y;
			return Math.sqrt(dx*dx + dy*dy);
		}
		
		public static function calcDistanceToLine(from:Point, to:Point, outter:Point):Number{
			var p:Point = MathUtil.calcClosestPointOnLine(from, to, outter);
			return MathUtil.calcDistance(outter, p);
		}
	}	
}